#pragma once

//////////
// attr //
//////////

template <class T> class xattr {
private:
	const string &	name;
	T &				value;
public:
	xattr(const string & n, T & v)
		: name(n), value(v) { }
	void operator () (stream & s)
	{
		if (s.in())	{
			value = s.root().attr<T>(name);
		} else {
			s.root().attr<T>(name, value);
		}
	}
};

template <class T> 
inline manipulator< xattr<T> > attr(const string & name, T & value)
	{ return manip(xattr<T>(name, value)); }

//////////////
// def_attr //
//////////////

template <class T> class xdef_attr {
private:
	const string &	name;
	T &				value;
	const T &		def_value;
public:
	xdef_attr(const string & n, T & v, const T & d)
		: name(n), value(v), def_value(d) { }
	void operator () (stream & s)
	{
		if (s.in())	{
			value = s.root().attr<T>(name, def_t<T>(def_value));
		} else {
			if (value != def_value)
				s.root().attr<T>(name, value);
		}
	}
};

template <class T> 
inline manipulator< xdef_attr<T> > def_attr(const string & name, T & value, const T & def)
	{ return manip(xdef_attr<T>(name, value, def)); }

/////////////////
// def_in_attr //
/////////////////

template <class T> class xdef_in_attr {
private:
	const string &	name;
	T &				value;
	const T &		def_value;
public:
	xdef_in_attr(const string & n, T & v, const T & d)
		: name(n), value(v), def_value(d) { }
	void operator () (stream & s)
	{
		if (s.in())	{
			value = s.root().attr<T>(name, def_t<T>(def_value));
		} else {
			s.root().attr<T>(name, value);
		}
	}
};

template <class T> 
inline manipulator< xdef_in_attr<T> > def_in_attr(const string & name, T & value, const T & def)
	{ return manip(xdef_in_attr<T>(name, value, def)); }
